package org.mmtk.plan.scale.balance;

import org.mmtk.plan.Phase;
import org.mmtk.plan.TransitiveClosure;
import org.mmtk.plan.scale.Scale;
import org.mmtk.utility.Log;
import org.mmtk.utility.options.Options;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Interruptible;
import org.vmmagic.pragma.Uninterruptible;

@Uninterruptible
public class SBalance extends Scale {	
	/****************************************************************************
	 * Class variables
	 */
	static final short MetrixFixMetrix_ClosurePhase = Phase.createComplex(
			"MetrixFixMetrix_ClosurePhase", 
			null, 
			Phase.scheduleMutator(PREPARE), 
			Phase.scheduleGlobal(PREPARE), 
			Phase.scheduleCollector(PREPARE),
			Phase.scheduleComplex(prepareStacks), 
			Phase.scheduleCollector(STACK_ROOTS), 
			Phase.scheduleCollector(ROOTS), 
			Phase.scheduleGlobal(ROOTS),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(depthClosure),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(fixClosure),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(depthCheckClosure));
	
	static final short TFT_ClosurePhase = Phase.createComplex(
			"TFT_ClosurePhase", 
			null, 
			Phase.scheduleMutator(PREPARE), 
			Phase.scheduleGlobal(PREPARE), 
			Phase.scheduleCollector(PREPARE),
			Phase.scheduleComplex(prepareStacks), 
			Phase.scheduleCollector(STACK_ROOTS), 
			Phase.scheduleCollector(ROOTS), 
			Phase.scheduleGlobal(ROOTS),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(regClosure),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(fixClosure),
			Phase.scheduleGlobal(prepareClosure),
			Phase.scheduleCollector(prepareClosure),
			Phase.scheduleGlobal(CLOSURE), 
			Phase.scheduleCollector(regClosure));
	
	static final int METRIX_FIX_METRIX_FLAVOR = 21;	//balancer depth
	static final int TIME_FIX_TIME_FLAVOR = 22;		//balancer timer
	public static final int SCAN_BALANCE = 2;
	public static final int PRIVATE_SCAN_BALANCE = 3;
	/****************************************************************************
	 * Instance variables
	 */

	public final TraceBranchBalancer ballancer = new TraceBranchBalancer();
	/*****************************************************************************
	 * 
	 * Collection
	 */
	public SBalance() {
		super();
	    
		Options.sbDistance = new SBDistanceOption();
		Options.sbMaxRefs = new SBMaxRefsOption();
		Options.sbRatio = new SBRatioOption();
		Options.sbSize = new SBSizeOption();
		Options.sbSkip = new SBSkipOption();
	}
	
	/**
	 * Perform a (global) collection phase.
	 * 
	 * @param phaseId
	 *            Collection phase to execute.
	 */
	@Inline
	@Override
	public void collectionPhase(short phaseId) {
		super.collectionPhase(phaseId);
	}
				
	@Override
	protected void doSetFirstClosureType() {
		if(traceFlavor == TIME_FIX_TIME_FLAVOR){
			closure = CLOSURE_FIRST_CONCURRENT;
		} else {
			closure = CLOSURE_FIRST_SINGLE;
		} 
	}
	
	@Override
	protected void doSetNextClosureType() {
		if(traceFlavor == METRIX_FIX_METRIX_FLAVOR) {
			if(closure == CLOSURE_FIRST_SINGLE ) {	
				closure = CLOSURE_SINGLE;
			} else if (closure == CLOSURE_SINGLE) {
				closure = CLOSURE_LAST_SINGLE;
			}
		} else if(traceFlavor == TIME_FIX_TIME_FLAVOR){
			if(closure == CLOSURE_FIRST_CONCURRENT) {
				closure = CLOSURE_SINGLE;
			} else if (closure == CLOSURE_SINGLE) {
				closure = CLOSURE_LAST_CONCURRENT;
			}
		} 
	}
	
	@Override
	protected short getReplacementPhaseID() {
		if(traceFlavor == METRIX_FIX_METRIX_FLAVOR) {
			return MetrixFixMetrix_ClosurePhase;		
		} else if(traceFlavor == TIME_FIX_TIME_FLAVOR) {
			return TFT_ClosurePhase;	
		} 
		return -1;
	}

	/**
	 * Register specialized methods.
	 */
	@Interruptible
	@Override
	protected void registerSpecializedMethods() {
		super.registerSpecializedMethods();
		TransitiveClosure.registerSpecializedScan(SCAN_BALANCE, SBalanceTraceLocal.class);
		TransitiveClosure.registerSpecializedScan(PRIVATE_SCAN_BALANCE, SBalanceTraceLocal.class);	
	}
	
	@Interruptible
	@Override
	protected void initializeRun() {
		traceFlavor = METRIX_FIX_METRIX_FLAVOR;
		super.initializeRun();
		//no need to scan
		scanner = null;
		
		Log.write("SB options: sbDistance=");
		Log.write(Options.sbDistance.getValue());
		Log.write(", sbMaxRefs=");
		Log.write(Options.sbMaxRefs.getValue());
		Log.write(", sbRatio=");
		Log.write(Options.sbRatio.getValue());
		Log.write(", sbSize=");
		Log.write(Options.sbSize.getValue());
		Log.write(", sbSkip=");
		Log.writeln(Options.sbSkip.getValue());
	}
}
